package com.atguigu.srb.core.service.impl;

import com.alibaba.excel.EasyExcel;
import com.atguigu.srb.core.dto.ExcelDictDTO;
import com.atguigu.srb.core.entity.Dict;
import com.atguigu.srb.core.listener.ExcelDictDTOListener;
import com.atguigu.srb.core.mapper.DictMapper;
import com.atguigu.srb.core.service.DictService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author ccy
 * @since 2025-04-09
 */
@Slf4j
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {


    @Resource
    private RedisTemplate redisTemplate;


    //添加事务，若导入过程中出现错误，则全部回滚(防止数据导入一半，一半留在表中，一半没有留在表中)
    //事务成功全部导入，事务不成功就全部不导入
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importData(InputStream inputStream) {

        EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOListener(baseMapper)).sheet().doRead();
        log.info("Excel导入成功");
    }

    @Override
    public List<ExcelDictDTO> listDictData() {

        //没有任何条件就使用null
        List<Dict> dicts = baseMapper.selectList(null);

        //创建ExcelDictDTO列表，将Dict列表转换为ExcelDictDTO列表

        List<ExcelDictDTO> excelDictDTOList = new ArrayList<>();
        for (Dict dict : dicts) {
            ExcelDictDTO excelDictDTO = new ExcelDictDTO();
            BeanUtils.copyProperties(dict, excelDictDTO);
            excelDictDTOList.add(excelDictDTO);
        }

        return excelDictDTOList;
    }

    @Override
    public List<Dict> listByParentId(Long parentId) {

        //用try-catch的原因是redis调用可能出错
        try {

            //首先查询redis中是否存在数据列表
            List<Dict> dictList = (List<Dict>) redisTemplate.opsForValue().get("srb:core:dictList" + parentId);

            //如果存在，则从redis中直接返回数据列表
            if (dictList != null) {
                log.info("从redis中获取数据列表");
                return dictList;
            }

        } catch (Exception e) {
            //ExceptionUtils.getStackTrace(e): 拿到e对象错误跟踪栈字符串
            log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
        }

        // 如果不存在，则从数据库中查询，并把数据保存到redis中
        log.info("从数据库中获取数据列表");
        LambdaQueryWrapper<Dict> qW = Wrappers.lambdaQuery();
        qW.eq(Dict::getParentId, parentId);
        List<Dict> dictList = this.list(qW);
        //填充hashChildren字段
        dictList.forEach(dict -> {
            //判断当前节点是否有子节点，找到当前的dict下级是否有子节点
            boolean hasChildren = this.hasChildren(dict.getId());
            dict.setHasChildren(hasChildren);
        });

        try {
            //将数据存入redis
            log.info("将数据存入redis");
            redisTemplate.opsForValue().set("srb:core:dictList" + parentId, dictList, 5, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
        }

        //返回数据列表
        return dictList;
    }

    /**
     * 判断当前节点是否有子节点
     * @param id 参数
     * @return boolean
     */
    private boolean hasChildren(Long id) {
        LambdaQueryWrapper<Dict> qW = Wrappers.lambdaQuery();
        qW.eq(Dict::getParentId, id);
//        int count = this.count(qW);
        if (this.count(qW) > 0) {
            return true;
        }

        return false;
    }
}
